<template>
	<el-dialog v-model="dialogVisible" :close-on-click-modal="false" :close-on-press-escape="false" :show-close="false"
	           :title="props.title"
	           center class="cus-dialog" draggable width="50%">
		<el-row>
			<el-col :offset="12" :span="12">预览：</el-col>
		</el-row>
		<div class="cropper">
			<!-- 裁剪左侧内容-->
			<div class="cropper_left">
				<vueCropper
						ref="cropperRef"
						:auto-crop="options.autoCrop"
						:autoCropHeight="options.autoCropHeight"
						:autoCropWidth="options.autoCropWidth"
						:can-move="options.canMoveBox"
						:can-scale="options.canScale"
						:center-box="options.centerBox"
						:fixed="options.fixed"
						:fixed-box="options.fixedBox"
						:fixed-number="fixedNumber"
						:full="options.full"
						:img="img"
						:info="options.info"
						:info-true="options.infoTrue"
						output-type="png"
						@real-time="previewHandle"
				/>
				<div class="reupload_box">
					<icon name="el-icon-CirclePlus" style="cursor: pointer" @click="changeScale(3)"/>
					<icon name="el-icon-Remove" style="margin-left: 10px;cursor: pointer" @click="changeScale(-3)"/>
					<icon name="el-icon-RefreshRight" style="margin-left: 10px;cursor: pointer" @click="rotateRight"/>
				</div>
			</div>
			<div class="cropper_right">
				<div :style="previewFileStyle">
					<el-image :src="previews.url" :style="previews.img" fit="contain"/>
				</div>
			</div>
		</div>
		<template #footer>
			<el-button icon="el-icon-CircleCheck" type="primary" @click="onConfirm">确认</el-button>
			<el-button icon="el-icon-Refresh" @click="refreshCrop">重置</el-button>
			<el-button icon="el-icon-CircleClose" type="warning" @click="onCancel">取消</el-button>
		</template>
	</el-dialog>
</template>

<script lang="ts" setup>
// 需要引入的库
import 'vue-cropper/dist/index.js'
import VueCropper from 'vue-cropper/src/vue-cropper.vue'
import {computed, reactive, ref} from 'vue'
import Icon from '@/components/icon.vue'

// 父组件传参props
interface IProps {
	visible: boolean
	img: string | ArrayBuffer | null // 裁剪图片的地址
	fileName: string // 裁剪后生成的文件名
	type: string // 上传类型, 企业logo / 浏览器logo
	limitSize: number // 限制大小
	fixedNumber: [number, number] // 宽高比 w/h
	fixedNumberAider?: number[] // 侧边栏收起截图框的宽高比例
	previewWidth: number // 预览宽度
	title?: string // 裁剪标题
}

/* 父组件传参 */
const props = withDefaults(defineProps<IProps>(), {
	visible: false,
	type: 'systemLogo',
	limitSize: 1,
	fixedNumber: () => [1, 1],
	fixedNumberAider: () => [1, 1],
	previewWidth: 228,
	title: '图片裁剪'
})

// 裁剪组件需要使用到的参数
interface Options {
	info: boolean // 裁剪框的大小信息
	outputSize: number // 裁剪生成图片的质量 [1至0.1]
	outputType: string // 裁剪生成图片的格式
	canScale: boolean // 是否开启滚轮放大缩小
	autoCrop: boolean // 是否自动生成截图框
	autoCropWidth: number // 默认生成截图框宽度
	autoCropHeight: number // 默认生成截图框高度
	fixedBox: boolean // 固定大小 禁止改变截图框大小
	fixed: boolean // 是否开启固定宽高比
	fixedNumber: [number, number] // 宽高比 w/h
	full: boolean // 输出截图是否缩放
	canMoveBox: boolean // 是否可以拖动图片
	original: boolean // 上传图片按照原始比例渲染
	centerBox: boolean // 截图框是否限制在图片内部
	infoTrue: boolean // true 为展示真实输出图片宽高 false 展示看到的截图框宽高
	accept: string // 上传允许的格式
}

// 裁剪组件需要使用到的参数
const options = reactive<Options>({
	autoCrop: true, // 是否自动生成截图框
	autoCropWidth: 150, // 默认生成截图框的宽度
	autoCropHeight: 150, // 默认生成截图框的长度
	fixedBox: false, // 固定大小 禁止改变截图框大小
	info: false, // 裁剪框的大小信息
	outputSize: 1, // 裁剪生成图片的质量 [1至0.1]
	outputType: 'png', // 裁剪生成图片的格式
	canScale: true, // 是否开启滚轮放大缩小
	fixed: true, // 是否开启固定宽高比
	fixedNumber: [1, 1], // 宽高比 w/h
	full: true, // 输出截图是否缩放
	canMoveBox: false, // 是否可以拖动图片
	original: false, // 上传图片按照原始比例渲染
	centerBox: true, // 截图框是否限制在图片内部
	infoTrue: false, // true 为展示真实输出图片宽高 false 展示看到的截图框宽高
	accept: 'image/jpeg,image/jpg,image/png,image/gif,image/x-icon'
})

const emits = defineEmits(['confirm', 'cancel', 'update:visible'])

const dialogVisible = computed({
	get: () => {
		return props.visible
	},
	set: value => {
		emits('update:visible', value)
	}
})

// 裁剪后的预览样式信息
const previews: any = ref({})
const previewFileStyle = ref({})

// 裁剪组件Ref
const cropperRef: any = ref({})

/* 重置裁剪组件 */
const refreshCrop = () => {
	// cropperRef裁剪组件自带很多方法，可以打印看看
	cropperRef.value.refresh()
}

/* 右旋转图片 */
const rotateRight = () => {
	cropperRef.value.rotateRight()
}

/* 放大缩小图片比例 */
const changeScale = (num: number) => {
	const scale = num || 1
	cropperRef.value.changeScale(scale)
}

// 缩放的格式
const tempScale = ref<number>(0)

// base64转图片文件
const dataURLtoFile = (dataUrl: string, filename: string) => {
	const arr = dataUrl.split(',')
	const mime = arr[0].match(/:(.*?);/)![1]
	const bstr = atob(arr[1])
	let len = bstr.length
	const u8arr = new Uint8Array(len)
	while (len--) {
		u8arr[len] = bstr.charCodeAt(len)
	}
	return new File([u8arr], filename, {type: mime})
}

const onConfirm = () => {
	cropperRef.value.getCropData(async (data: string) => {
		const dataFile: File = dataURLtoFile(data, props.fileName)
		// 触发自定义事件
		emits('confirm', dataFile)
	})
	dialogVisible.value = false
}

const onCancel = () => {
	emits('cancel')
	dialogVisible.value = false
}

// 裁剪之后的数据
const previewHandle = (data: any) => {
	previews.value = data // 预览img图片
	tempScale.value = props.previewWidth / data.w
	previewFileStyle.value = {
		width: data.w + 'px',
		height: data.h + 'px',
		// width: '200px',
		// height: '200px',
		margin: 0,
		overflow: 'hidden',
		zoom: tempScale.value,
		position: 'relative',
		border: '1px solid #e8e8e8',
		'border-radius': '2px'
	}
}

</script>

<style lang="scss" scoped>
.cropper {
	display: flex;
	height: 50vh;
	overflow: hidden;
	width: 100%;

	.cropper_left {
		display: flex;
		flex-direction: column;
		width: 45%;

		.reupload_box {
			align-items: center;
			display: flex;
			justify-content: center;
			margin-top: 10px;
		}
	}

	.cropper_right {
		flex: 1;
		margin-left: 10%;
		width: 45%;
	}
}
</style>
